home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Online / cnetdevice / src / include / ref / if_ne.c < prev    next >
C/C++ Source or Header  |  1991-06-21  |  20KB  |  797 lines

  1. /*-
  2.  * Copyright (c) 1990, 1991 William F. Jolitz.
  3.  * Copyright (c) 1990 The Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  *    This product includes software developed by the University of
  17.  *    California, Berkeley and its contributors.
  18.  * 4. Neither the name of the University nor the names of its contributors
  19.  *    may be used to endorse or promote products derived from this software
  20.  *    without specific prior written permission.
  21.  *
  22.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32.  * SUCH DAMAGE.
  33.  *
  34.  *    @(#)if_ne.c    7.4 (Berkeley) 5/21/91
  35.  */
  36.  
  37. /*
  38.  * NE2000 Ethernet driver
  39.  *
  40.  * Parts inspired from Tim Tucker's if_wd driver for the wd8003,
  41.  * insight on the ne2000 gained from Robert Clements PC/FTP driver.
  42.  */
  43.  
  44. #include "ne.h"
  45. #if NNE > 0
  46.  
  47. #include "param.h"
  48. #include "systm.h"
  49. #include "mbuf.h"
  50. #include "buf.h"
  51. #include "protosw.h"
  52. #include "socket.h"
  53. #include "ioctl.h"
  54. #include "errno.h"
  55. #include "syslog.h"
  56.  
  57. #include "net/if.h"
  58. #include "net/netisr.h"
  59. #include "net/route.h"
  60.  
  61. #ifdef INET
  62. #include "netinet/in.h"
  63. #include "netinet/in_systm.h"
  64. #include "netinet/in_var.h"
  65. #include "netinet/ip.h"
  66. #include "netinet/if_ether.h"
  67. #endif
  68.  
  69. #ifdef NS
  70. #include "netns/ns.h"
  71. #include "netns/ns_if.h"
  72. #endif
  73.  
  74. #include "i386/isa/isa_device.h"
  75. #include "i386/isa/if_nereg.h"
  76. #include "i386/isa/icu.h"
  77.  
  78. int    neprobe(), neattach(), neintr();
  79. int    nestart(),neinit(), ether_output(), neioctl();
  80.  
  81. struct    isa_driver nedriver = {
  82.     neprobe, neattach, "ne",
  83. };
  84.  
  85. struct    mbuf *neget();
  86.  
  87. #define ETHER_MIN_LEN 64
  88. #define ETHER_MAX_LEN 1536
  89.  
  90. /*
  91.  * Ethernet software status per interface.
  92.  *
  93.  * Each interface is referenced by a network interface structure,
  94.  * ns_if, which the routing code uses to locate the interface.
  95.  * This structure contains the output queue for the interface, its address, ...
  96.  */
  97. struct    ne_softc {
  98.     struct    arpcom ns_ac;        /* Ethernet common part */
  99. #define    ns_if    ns_ac.ac_if        /* network-visible interface */
  100. #define    ns_addr    ns_ac.ac_enaddr        /* hardware Ethernet address */
  101.     int    ns_flags;
  102. #define    DSF_LOCK    1        /* block re-entering enstart */
  103.     int    ns_oactive ;
  104.     int    ns_mask ;
  105.     int    ns_ba;            /* byte addr in buffer ram of inc pkt */
  106.     int    ns_cur;            /* current page being filled */
  107.     struct    prhdr    ns_ph;        /* hardware header of incoming packet*/
  108.     struct    ether_header ns_eh;    /* header of incoming packet */
  109.     u_char    ns_pb[2048 /*ETHERMTU+sizeof(long)*/];
  110. } ne_softc[NNE] ;
  111. #define    ENBUFSIZE    (sizeof(struct ether_header) + ETHERMTU + 2 + ETHER_MIN_LEN)
  112.  
  113. int nec;
  114.  
  115. u_short boarddata[16];
  116.  
  117. neprobe(dvp)
  118.     struct isa_device *dvp;
  119. {
  120.     int val,i,s;
  121.     register struct ne_softc *ns = &ne_softc[0];
  122.  
  123. #ifdef lint
  124.     neintr(0);
  125. #endif
  126.  
  127.     nec = dvp->id_iobase;
  128.     s = splimp();
  129.  
  130.     /* Reset the bastard */
  131.     val = inb(nec+ne_reset);
  132.     DELAY(2000000);
  133.     outb(nec+ne_reset,val);
  134.  
  135.     outb(nec+ds_cmd, DSCM_STOP|DSCM_NODMA);
  136.     
  137.     i = 1000000;
  138.     while ((inb(nec+ds0_isr)&DSIS_RESET) == 0 && i-- > 0);
  139.     if (i < 0) return (0);
  140.  
  141.     outb(nec+ds0_isr, 0xff);
  142.  
  143.     /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
  144.     outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
  145.  
  146.     outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
  147.     DELAY(10000);
  148.  
  149.     /* Check cmd reg and fail if not right */
  150.     if ((i=inb(nec+ds_cmd)) != (DSCM_NODMA|DSCM_PG0|DSCM_STOP))
  151.         return(0);
  152.  
  153.     outb(nec+ds0_tcr, 0);
  154.     outb(nec+ds0_rcr, DSRC_MON);
  155.     outb(nec+ds0_pstart, RBUF/DS_PGSIZE);
  156.     outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE);
  157.     outb(nec+ds0_bnry, RBUFEND/DS_PGSIZE);
  158.     outb(nec+ds0_imr, 0);
  159.     outb(nec+ds0_isr, 0);
  160.     outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
  161.     outb(nec+ds1_curr, RBUF/DS_PGSIZE);
  162.     outb(nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
  163.  
  164. #ifdef NEDEBUG
  165. #define    PAT(n)    (0xa55a + 37*(n))
  166. #define    RCON    37
  167.     {    int i, rom, pat;
  168.  
  169.         rom=1;
  170.         printf("ne ram ");
  171.         
  172.         for (i = 0; i < 0xfff0; i+=4) {
  173.             pat = PAT(i);
  174.             neput(&pat,i,4);
  175.             nefetch(&pat,i,4);
  176.             if (pat == PAT(i)) {
  177.                 if (rom) {
  178.                     rom=0;
  179.                     printf(" %x", i);
  180.                 }
  181.             } else {
  182.                 if (!rom) {
  183.                     rom=1;
  184.                     printf("..%x ", i);
  185.                 }
  186.             }
  187.             pat=0;
  188.             neput(&pat,i,4);
  189.         }
  190.         printf("\n");
  191.     }
  192. #endif
  193.  
  194.     /* Extract board address */
  195.     nefetch ((caddr_t)boarddata, 0, sizeof(boarddata));
  196.     for(i=0; i < 6; i++)  ns->ns_addr[i] = boarddata[i];
  197.     splx(s);
  198.     return (1);
  199. }
  200.  
  201. /*
  202.  * Fetch from onboard ROM/RAM
  203.  */
  204. nefetch (up, ad, len) caddr_t up; {
  205.     u_char cmd;
  206.  
  207.     cmd = inb(nec+ds_cmd);
  208.     outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
  209.  
  210.     /* Setup remote dma */
  211.     outb (nec+ds0_isr, DSIS_RDC);
  212.     outb (nec+ds0_rbcr0, len);
  213.     outb (nec+ds0_rbcr1, len>>8);
  214.     outb (nec+ds0_rsar0, ad);
  215.     outb (nec+ds0_rsar1, ad>>8);
  216.  
  217.     /* Execute & extract from card */
  218.     outb (nec+ds_cmd, DSCM_RREAD|DSCM_PG0|DSCM_START);
  219.     insw (nec+ne_data, up, len/2);
  220.  
  221.     /* Wait till done, then shutdown feature */
  222.     while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) ;
  223.     outb (nec+ds0_isr, DSIS_RDC);
  224.     outb (nec+ds_cmd, cmd);
  225. }
  226.  
  227. /*
  228.  * Put to onboard RAM
  229.  */
  230. neput (up, ad, len) caddr_t up; {
  231.     u_char cmd;
  232.  
  233.     cmd = inb(nec+ds_cmd);
  234.     outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
  235.  
  236.     /* Setup for remote dma */
  237.     outb (nec+ds0_isr, DSIS_RDC);
  238.     if(len&1) len++;        /* roundup to words */
  239.     outb (nec+ds0_rbcr0, len);
  240.     outb (nec+ds0_rbcr1, len>>8);
  241.     outb (nec+ds0_rsar0, ad);
  242.     outb (nec+ds0_rsar1, ad>>8);
  243.  
  244.     /* Execute & stuff to card */
  245.     outb (nec+ds_cmd, DSCM_RWRITE|DSCM_PG0|DSCM_START);
  246.     outsw (nec+ne_data, up, len/2);
  247.     
  248.     /* Wait till done, then shutdown feature */
  249.     while ((inb (nec+ds0_isr) & DSIS_RDC) == 0) ;
  250.     outb (nec+ds0_isr, DSIS_RDC);
  251.     outb (nec+ds_cmd, cmd);
  252. }
  253.  
  254. /*
  255.  * Reset of interface.
  256.  */
  257. nereset(unit, uban)
  258.     int unit, uban;
  259. {
  260.     if (unit >= NNE)
  261.         return;
  262.     printf("ne%d: reset\n", unit);
  263.     ne_softc[unit].ns_flags &= ~DSF_LOCK;
  264.     neinit(unit);
  265. }
  266.  
  267. /*
  268.  * Interface exists: make available by filling in network interface
  269.  * record.  System will initialize the interface when it is ready
  270.  * to accept packets.  We get the ethernet address here.
  271.  */
  272. neattach(dvp)
  273.     struct isa_device *dvp;
  274. {
  275.     int unit = dvp->id_unit;
  276.     register struct ne_softc *ns = &ne_softc[unit];
  277.     register struct ifnet *ifp = &ns->ns_if;
  278.  
  279.     ifp->if_unit = unit;
  280.     ifp->if_name = nedriver.name ;
  281.     ifp->if_mtu = ETHERMTU;
  282.     printf (" ethernet address %s", ether_sprintf(ns->ns_addr)) ;
  283.     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
  284.     ifp->if_init = neinit;
  285.     ifp->if_output = ether_output;
  286.     ifp->if_start = nestart;
  287.     ifp->if_ioctl = neioctl;
  288.     ifp->if_reset = nereset;
  289.     ifp->if_watchdog = 0;
  290.     if_attach(ifp);
  291. }
  292.  
  293. /*
  294.  * Initialization of interface; set up initialization block
  295.  * and transmit/receive descriptor rings.
  296.  */
  297. neinit(unit)
  298.     int unit;
  299. {
  300.     register struct ne_softc *ns = &ne_softc[unit];
  301.     struct ifnet *ifp = &ns->ns_if;
  302.     int s;
  303.     register i; char *cp;
  304.  
  305.      if (ifp->if_addrlist == (struct ifaddr *)0) return;
  306.     if (ifp->if_flags & IFF_RUNNING) return;
  307.  
  308.     s = splimp();
  309.  
  310.     /* set physical address on ethernet */
  311.     outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
  312.     for (i=0 ; i < 6 ; i++) outb(nec+ds1_par0+i,ns->ns_addr[i]);
  313.  
  314.     /* clr logical address hash filter for now */
  315.     for (i=0 ; i < 8 ; i++) outb(nec+ds1_mar0+i,0xff);
  316.  
  317.     /* init regs */
  318.     outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_STOP);
  319.     outb (nec+ds0_rbcr0, 0);
  320.     outb (nec+ds0_rbcr1, 0);
  321.     outb (nec+ds0_imr, 0);
  322.     outb (nec+ds0_isr, 0xff);
  323.  
  324.     /* Word Transfers, Burst Mode Select, Fifo at 8 bytes */
  325.     outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
  326.     outb(nec+ds0_tcr, 0);
  327.     outb (nec+ds0_rcr, DSRC_MON);
  328.     outb (nec+ds0_tpsr, 0);
  329.     outb(nec+ds0_pstart, RBUF/DS_PGSIZE);
  330.     outb(nec+ds0_pstop, RBUFEND/DS_PGSIZE);
  331.     outb(nec+ds0_bnry, RBUF/DS_PGSIZE);
  332.     outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG1|DSCM_STOP);
  333.     outb(nec+ds1_curr, RBUF/DS_PGSIZE);
  334.     ns->ns_cur = RBUF/DS_PGSIZE;
  335.     outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
  336.     outb (nec+ds0_rcr, DSRC_AB);
  337.     outb(nec+ds0_dcr, DSDC_WTS|DSDC_BMS|DSDC_FT1);
  338.     outb (nec+ds0_imr, 0xff);
  339.  
  340.     ns->ns_if.if_flags |= IFF_RUNNING;
  341.     ns->ns_oactive = 0; ns->ns_mask = ~0;
  342.     nestart(ifp);
  343.     splx(s);
  344. }
  345.  
  346. /*
  347.  * Setup output on interface.
  348.  * Get another datagram to send off of the interface queue,
  349.  * and map it to the interface before starting the output.
  350.  * called only at splimp or interrupt level.
  351.  */
  352. nestart(ifp)
  353.     struct ifnet *ifp;
  354. {
  355.     register struct ne_softc *ns = &ne_softc[ifp->if_unit];
  356.     struct mbuf *m0, *m;
  357.     int buffer;
  358.     int len = 0, i, total,t;
  359.  
  360.     /*
  361.      * The DS8390 has only one transmit buffer, if it is busy we
  362.      * must wait until the transmit interrupt completes.
  363.      */
  364.     outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
  365.  
  366.     if (ns->ns_flags & DSF_LOCK)
  367.         return;
  368.  
  369.     if (inb(nec+ds_cmd) & DSCM_TRANS)
  370.         return;
  371.  
  372.     if ((ns->ns_if.if_flags & IFF_RUNNING) == 0)
  373.         return;
  374.  
  375.     IF_DEQUEUE(&ns->ns_if.if_snd, m);
  376.  
  377.     if (m == 0)
  378.         return;
  379.  
  380.     /*
  381.      * Copy the mbuf chain into the transmit buffer
  382.      */
  383.  
  384.     ns->ns_flags |= DSF_LOCK;    /* prevent entering nestart */
  385.     buffer = TBUF; len = i = 0;
  386.     t = 0;
  387.     for (m0 = m; m != 0; m = m->m_next)
  388.         t += m->m_len;
  389.         
  390.     m = m0;
  391.     total = t;
  392.     for (m0 = m; m != 0; ) {
  393.         
  394.         if (m->m_len&1 && t > m->m_len) {
  395.             neput(mtod(m, caddr_t), buffer, m->m_len - 1);
  396.             t -= m->m_len - 1;
  397.             buffer += m->m_len - 1;
  398.             m->m_data += m->m_len - 1;
  399.             m->m_len = 1;
  400.             m = m_pullup(m, 2);
  401.         } else {
  402.             neput(mtod(m, caddr_t), buffer, m->m_len);
  403.             buffer += m->m_len;
  404.             t -= m->m_len;
  405.             MFREE(m, m0);
  406.             m = m0;
  407.         }
  408.     }
  409.  
  410.     /*
  411.      * Init transmit length registers, and set transmit start flag.
  412.      */
  413.  
  414.     len = total;
  415.     if (len < ETHER_MIN_LEN) len = ETHER_MIN_LEN;
  416.     outb(nec+ds0_tbcr0,len&0xff);
  417.     outb(nec+ds0_tbcr1,(len>>8)&0xff);
  418.     outb(nec+ds0_tpsr, TBUF/DS_PGSIZE);
  419.     outb(nec+ds_cmd, DSCM_TRANS|DSCM_NODMA|DSCM_START);
  420. }
  421.  
  422. /* buffer successor/predecessor in ring? */
  423. #define succ(n) (((n)+1 >= RBUFEND/DS_PGSIZE) ? RBUF/DS_PGSIZE : (n)+1)
  424. #define pred(n) (((n)-1 < RBUF/DS_PGSIZE) ? RBUFEND/DS_PGSIZE-1 : (n)-1)
  425.  
  426. /*
  427.  * Controller interrupt.
  428.  */
  429. neintr(unit)
  430. {
  431.     register struct ne_softc *ns = &ne_softc[unit];
  432.     u_char cmd,isr;
  433.  
  434.     /* Save cmd, clear interrupt */
  435.     cmd = inb (nec+ds_cmd);
  436. loop:
  437.     isr = inb (nec+ds0_isr);
  438.     outb(nec+ds_cmd,DSCM_NODMA|DSCM_START);
  439.     outb(nec+ds0_isr, isr);
  440.  
  441.     /* Receiver error */
  442.     if (isr & DSIS_RXE) {
  443.         /* need to read these registers to clear status */
  444.         (void) inb(nec+ ds0_rsr);
  445.         (void) inb(nec+ 0xD);
  446.         (void) inb(nec + 0xE);
  447.         (void) inb(nec + 0xF);
  448.         ns->ns_if.if_ierrors++;
  449.     }
  450.  
  451.     /* We received something; rummage thru tiny ring buffer */
  452.     if (isr & (DSIS_RX|DSIS_RXE|DSIS_ROVRN)) {
  453.         u_char pend,lastfree;
  454.  
  455.         outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
  456.         pend = inb(nec+ds1_curr);
  457.         outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
  458.         lastfree = inb(nec+ds0_bnry);
  459.  
  460.         /* Have we wrapped? */
  461.         if (lastfree >= RBUFEND/DS_PGSIZE)
  462.             lastfree = RBUF/DS_PGSIZE;
  463.         if (pend < lastfree && ns->ns_cur < pend)
  464.             lastfree = ns->ns_cur;
  465.         else    if (ns->ns_cur > lastfree)
  466.             lastfree = ns->ns_cur;
  467.  
  468.         /* Something in the buffer? */
  469.         while (pend != lastfree) {
  470.             u_char nxt;
  471.  
  472.             /* Extract header from microcephalic board */
  473.             nefetch(&ns->ns_ph,lastfree*DS_PGSIZE,
  474.                 sizeof(ns->ns_ph));
  475.             ns->ns_ba = lastfree*DS_PGSIZE+sizeof(ns->ns_ph);
  476.  
  477.             /* Incipient paranoia */
  478.             if (ns->ns_ph.pr_status == DSRS_RPC ||
  479.                 /* for dequna's */
  480.                 ns->ns_ph.pr_status == 0x21)
  481.                 nerecv (ns);
  482. #ifdef NEDEBUG
  483.             else  {
  484.                 printf("cur %x pnd %x lfr %x ",
  485.                     ns->ns_cur, pend, lastfree);
  486.                 printf("nxt %x len %x ", ns->ns_ph.pr_nxtpg,
  487.                     (ns->ns_ph.pr_sz1<<8)+ ns->ns_ph.pr_sz0);
  488.                 printf("Bogus Sts %x\n", ns->ns_ph.pr_status);    
  489.             }
  490. #endif
  491.  
  492.             nxt = ns->ns_ph.pr_nxtpg ;
  493.  
  494.             /* Sanity check */
  495.             if ( nxt >= RBUF/DS_PGSIZE && nxt <= RBUFEND/DS_PGSIZE
  496.                 && nxt <= pend)
  497.                 ns->ns_cur = nxt;
  498.             else    ns->ns_cur = nxt = pend;
  499.  
  500.             /* Set the boundaries */
  501.             lastfree = nxt;
  502.             outb(nec+ds0_bnry, pred(nxt));
  503.             outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG1);
  504.             pend = inb(nec+ds1_curr);
  505.             outb(nec+ds_cmd, DSCM_START|DSCM_NODMA|DSCM_PG0);
  506.         }
  507.         outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
  508.     }
  509.  
  510.     /* Transmit error */
  511.     if (isr & DSIS_TXE) {
  512.         ns->ns_flags &= ~DSF_LOCK;
  513.         /* Need to read these registers to clear status */
  514.         ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
  515.         ns->ns_if.if_oerrors++;
  516.     }
  517.  
  518.     /* Packet Transmitted */
  519.     if (isr & DSIS_TX) {
  520.         ns->ns_flags &= ~DSF_LOCK;
  521.         ++ns->ns_if.if_opackets;
  522.         ns->ns_if.if_collisions += inb(nec+ds0_tbcr0);
  523.     }
  524.  
  525.     /* Receiver ovverun? */
  526.     if (isr & DSIS_ROVRN) {
  527.         log(LOG_ERR, "ne%d: error: isr %x\n", ns-ne_softc, isr
  528.             /*, DSIS_BITS*/);
  529.         outb(nec+ds0_rbcr0, 0);
  530.         outb(nec+ds0_rbcr1, 0);
  531.         outb(nec+ds0_tcr, DSTC_LB0);
  532.         outb(nec+ds0_rcr, DSRC_MON);
  533.         outb(nec+ds_cmd, DSCM_START|DSCM_NODMA);
  534.         outb(nec+ds0_rcr, DSRC_AB);
  535.         outb(nec+ds0_tcr, 0);
  536.     }
  537.  
  538.     /* Any more to send? */
  539.     outb (nec+ds_cmd, DSCM_NODMA|DSCM_PG0|DSCM_START);
  540.     nestart(&ns->ns_if);
  541.     outb (nec+ds_cmd, cmd);
  542.     outb (nec+ds0_imr, 0xff);
  543.  
  544.     /* Still more to do? */
  545.     isr = inb (nec+ds0_isr);
  546.     if(isr) goto loop;
  547. }
  548.  
  549. /*
  550.  * Ethernet interface receiver interface.
  551.  * If input error just drop packet.
  552.  * Otherwise examine packet to determine type.  If can't determine length
  553.  * from type, then have to drop packet.  Othewise decapsulate
  554.  * packet based on type and pass to type specific higher-level
  555.  * input routine.
  556.  */
  557. nerecv(ns)
  558.     register struct ne_softc *ns;
  559. {
  560.     int len,i;
  561.  
  562.     ns->ns_if.if_ipackets++;
  563.     len = ns->ns_ph.pr_sz0 + (ns->ns_ph.pr_sz1<<8);
  564.     if(len < ETHER_MIN_LEN || len > ETHER_MAX_LEN)
  565.         return;
  566.  
  567.     /* this need not be so torturous - one/two bcopys at most into mbufs */
  568.     nefetch(ns->ns_pb, ns->ns_ba, min(len,DS_PGSIZE-sizeof(ns->ns_ph)));
  569.     if (len > DS_PGSIZE-sizeof(ns->ns_ph)) {
  570.         int l = len - (DS_PGSIZE-sizeof(ns->ns_ph)), b ;
  571.         u_char *p = ns->ns_pb + (DS_PGSIZE-sizeof(ns->ns_ph));
  572.  
  573.         if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
  574.         b = ns->ns_cur*DS_PGSIZE;
  575.         
  576.         while (l >= DS_PGSIZE) {
  577.             nefetch(p, b, DS_PGSIZE);
  578.             p += DS_PGSIZE; l -= DS_PGSIZE;
  579.             if(++ns->ns_cur > 0x7f) ns->ns_cur = 0x46;
  580.             b = ns->ns_cur*DS_PGSIZE;
  581.         }
  582.         if (l > 0)
  583.             nefetch(p, b, l);
  584.     }
  585.     /* don't forget checksum! */
  586.     len -= sizeof(struct ether_header) + sizeof(long);
  587.             
  588.     neread(ns,(caddr_t)(ns->ns_pb), len);
  589. }
  590.  
  591. /*
  592.  * Pass a packet to the higher levels.
  593.  * We deal with the trailer protocol here.
  594.  */
  595. neread(ns, buf, len)
  596.     register struct ne_softc *ns;
  597.     char *buf;
  598.     int len;
  599. {
  600.     register struct ether_header *eh;
  601.         struct mbuf *m;
  602.     int off, resid;
  603.     register struct ifqueue *inq;
  604.  
  605.     /*
  606.      * Deal with trailer protocol: if type is trailer type
  607.      * get true type from first 16-bit word past data.
  608.      * Remember that type was trailer by setting off.
  609.      */
  610.     eh = (struct ether_header *)buf;
  611.     eh->ether_type = ntohs((u_short)eh->ether_type);
  612. #define    nedataaddr(eh, off, type)    ((type)(((caddr_t)((eh)+1)+(off))))
  613.     if (eh->ether_type >= ETHERTYPE_TRAIL &&
  614.         eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
  615.         off = (eh->ether_type - ETHERTYPE_TRAIL) * 512;
  616.         if (off >= ETHERMTU) return;        /* sanity */
  617.         eh->ether_type = ntohs(*nedataaddr(eh, off, u_short *));
  618.         resid = ntohs(*(nedataaddr(eh, off+2, u_short *)));
  619.         if (off + resid > len) return;        /* sanity */
  620.         len = off + resid;
  621.     } else    off = 0;
  622.  
  623.     if (len == 0) return;
  624.  
  625.     /*
  626.      * Pull packet off interface.  Off is nonzero if packet
  627.      * has trailing header; neget will then force this header
  628.      * information to be at the front, but we still have to drop
  629.      * the type and length which are at the front of any trailer data.
  630.      */
  631.     m = neget(buf, len, off, &ns->ns_if);
  632.     if (m == 0) return;
  633.  
  634.     ether_input(&ns->ns_if, eh, m);
  635. }
  636.  
  637. /*
  638.  * Supporting routines
  639.  */
  640.  
  641. /*
  642.  * Pull read data off a interface.
  643.  * Len is length of data, with local net header stripped.
  644.  * Off is non-zero if a trailer protocol was used, and
  645.  * gives the offset of the trailer information.
  646.  * We copy the trailer information and then all the normal
  647.  * data into mbufs.  When full cluster sized units are present
  648.  * we copy into clusters.
  649.  */
  650. struct mbuf *
  651. neget(buf, totlen, off0, ifp)
  652.     caddr_t buf;
  653.     int totlen, off0;
  654.     struct ifnet *ifp;
  655. {
  656.     struct mbuf *top, **mp, *m, *p;
  657.     int off = off0, len;
  658.     register caddr_t cp = buf;
  659.     char *epkt;
  660.  
  661.     buf += sizeof(struct ether_header);
  662.     cp = buf;
  663.     epkt = cp + totlen;
  664.  
  665.  
  666.     if (off) {
  667.         cp += off + 2 * sizeof(u_short);
  668.         totlen -= 2 * sizeof(u_short);
  669.     }
  670.  
  671.     MGETHDR(m, M_DONTWAIT, MT_DATA);
  672.     if (m == 0)
  673.         return (0);
  674.     m->m_pkthdr.rcvif = ifp;
  675.     m->m_pkthdr.len = totlen;
  676.     m->m_len = MHLEN;
  677.  
  678.     top = 0;
  679.     mp = ⊤
  680.     while (totlen > 0) {
  681.         if (top) {
  682.             MGET(m, M_DONTWAIT, MT_DATA);
  683.             if (m == 0) {
  684.                 m_freem(top);
  685.                 return (0);
  686.             }
  687.             m->m_len = MLEN;
  688.         }
  689.         len = min(totlen, epkt - cp);
  690.         if (len >= MINCLSIZE) {
  691.             MCLGET(m, M_DONTWAIT);
  692.             if (m->m_flags & M_EXT)
  693.                 m->m_len = len = min(len, MCLBYTES);
  694.             else
  695.                 len = m->m_len;
  696.         } else {
  697.             /*
  698.              * Place initial small packet/header at end of mbuf.
  699.              */
  700.             if (len < m->m_len) {
  701.                 if (top == 0 && len + max_linkhdr <= m->m_len)
  702.                     m->m_data += max_linkhdr;
  703.                 m->m_len = len;
  704.             } else
  705.                 len = m->m_len;
  706.         }
  707.         bcopy(cp, mtod(m, caddr_t), (unsigned)len);
  708.         cp += len;
  709.         *mp = m;
  710.         mp = &m->m_next;
  711.         totlen -= len;
  712.         if (cp == epkt)
  713.             cp = buf;
  714.     }
  715.     return (top);
  716. }
  717.  
  718. /*
  719.  * Process an ioctl request.
  720.  */
  721. neioctl(ifp, cmd, data)
  722.     register struct ifnet *ifp;
  723.     int cmd;
  724.     caddr_t data;
  725. {
  726.     register struct ifaddr *ifa = (struct ifaddr *)data;
  727.     struct ne_softc *ns = &ne_softc[ifp->if_unit];
  728.     struct ifreq *ifr = (struct ifreq *)data;
  729.     int s = splimp(), error = 0;
  730.  
  731.  
  732.     switch (cmd) {
  733.  
  734.     case SIOCSIFADDR:
  735.         ifp->if_flags |= IFF_UP;
  736.  
  737.         switch (ifa->ifa_addr->sa_family) {
  738. #ifdef INET
  739.         case AF_INET:
  740.             neinit(ifp->if_unit);    /* before arpwhohas */
  741.             ((struct arpcom *)ifp)->ac_ipaddr =
  742.                 IA_SIN(ifa)->sin_addr;
  743.             arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
  744.             break;
  745. #endif
  746. #ifdef NS
  747.         case AF_NS:
  748.             {
  749.             register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
  750.  
  751.             if (ns_nullhost(*ina))
  752.                 ina->x_host = *(union ns_host *)(ns->ns_addr);
  753.             else {
  754.                 /* 
  755.                  * The manual says we can't change the address 
  756.                  * while the receiver is armed,
  757.                  * so reset everything
  758.                  */
  759.                 ifp->if_flags &= ~IFF_RUNNING; 
  760.                 bcopy((caddr_t)ina->x_host.c_host,
  761.                     (caddr_t)ns->ns_addr, sizeof(ns->ns_addr));
  762.             }
  763.             neinit(ifp->if_unit); /* does ne_setaddr() */
  764.             break;
  765.             }
  766. #endif
  767.         default:
  768.             neinit(ifp->if_unit);
  769.             break;
  770.         }
  771.         break;
  772.  
  773.     case SIOCSIFFLAGS:
  774.         if ((ifp->if_flags & IFF_UP) == 0 &&
  775.             ifp->if_flags & IFF_RUNNING) {
  776.             ifp->if_flags &= ~IFF_RUNNING;
  777.             outb(nec+ds_cmd,DSCM_STOP|DSCM_NODMA);
  778.         } else if (ifp->if_flags & IFF_UP &&
  779.             (ifp->if_flags & IFF_RUNNING) == 0)
  780.             neinit(ifp->if_unit);
  781.         break;
  782.  
  783. #ifdef notdef
  784.     case SIOCGHWADDR:
  785.         bcopy((caddr_t)ns->ns_addr, (caddr_t) &ifr->ifr_data,
  786.             sizeof(ns->ns_addr));
  787.         break;
  788. #endif
  789.  
  790.     default:
  791.         error = EINVAL;
  792.     }
  793.     splx(s);
  794.     return (error);
  795. }
  796. #endif
  797.